package com.forester.foresterplatform.system.config;

import com.forester.foresterplatform.system.security.ExceptionHandlerFilter;
import com.forester.foresterplatform.system.security.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig {

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

    @Autowired
    private ExceptionHandlerFilter exceptionHandlerFilter;

    /**
     * spring-security 可以放行的url
     */
    @Autowired
    private SecurityIgnoreUrl securityIgnoreUrl;

    /**
     * 替换默认passwordEncoder到容器中
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * AuthenticationManager 注入到容器
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManager(HttpSecurity http) throws Exception {
        return http.getSharedObject(AuthenticationManagerBuilder.class).build();
    }

    /**
     *
     * @param http
     * @throws Exception
     */
    @Bean
    protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        // 关闭 CSRF (针对前后端分离项目)
        http.csrf().disable();

        // 不通过 Session 获取 SecurityContext （分布式系统不适合用session）
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        // 配置角色访问
        http.authorizeRequests()
                // 没有认证成功的用户才能访问
                .antMatchers(securityIgnoreUrl.getAnonymousUrls()).anonymous()
                // permit 接口 携不携带 Authentication 都能访问
                .antMatchers(securityIgnoreUrl.getPermitAllUrls()).permitAll()
                // 除上述两种接口外的其他接口均需鉴权
                .anyRequest().authenticated();

        // 过滤器链配置
        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
            .addFilterBefore(exceptionHandlerFilter, LogoutFilter.class);
        return http.build();
    }
}

